﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Json;
using Windows.Security.Cryptography.Core;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Net.NetworkInformation;
using System.Windows;
using System.Security;
using GalaSoft.MvvmLight.Messaging;
using JmShared;
using System.ComponentModel;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using Windows.UI.Text;
using Windows.UI.Notifications;
using System.IO;
using Windows.Storage;
using Windows.Foundation;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Reflection;
using Windows.ApplicationModel;
using Windows.Data.Xml.Dom;
using JiveMessenger.Log;
using System.Text.RegularExpressions;
using Windows.UI.Xaml;
using Windows.Graphics.Display;
using Windows.Networking.Connectivity;



namespace JiveMessenger.Utilities
{
    public static partial class StaticMethods
    {
        //private static Dictionary<string, BitmapImage> StoredImageCache = new Dictionary<string, BitmapImage>();

        public static double GetScreenSizeInInches()
        {
            var displayInfo = Windows.Graphics.Display.DisplayInformation.GetForCurrentView();

            var width = Window.Current.Bounds.Width * (int)DisplayProperties.ResolutionScale / 100;
            var height = Window.Current.Bounds.Height * (int)DisplayProperties.ResolutionScale / 100;

            var dpi = DisplayInformation.GetForCurrentView().RawDpiY;

            var screenDiagonal = Math.Sqrt(Math.Pow(width / dpi, 2) +
                        Math.Pow(height / dpi, 2));

            return screenDiagonal;
        }

        public static bool GetIsInternetAvailable()
        {
            bool isConnected = NetworkInterface.GetIsNetworkAvailable();
            if (!isConnected)
            {
                isConnected = false;// await new MessageDialog("No internet connection is avaliable. The full functionality of the app isn't avaliable.").ShowAsync();
            }
            else
            {
                ConnectionProfile InternetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
                NetworkConnectivityLevel connection = InternetConnectionProfile.GetNetworkConnectivityLevel();
                if (connection == NetworkConnectivityLevel.None || connection == NetworkConnectivityLevel.LocalAccess)
                {
                    isConnected = false;
                }
            }
            return isConnected;
        }

        public static ToastNotification DisplayToast(string message, string title, bool silent = true)
        {
            var toastTemplate = ToastTemplateType.ToastImageAndText04;
            var toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
            var toastTextElements = toastXml.GetElementsByTagName("text");
            toastTextElements[0].AppendChild(toastXml.CreateTextNode(title));
            toastTextElements[1].AppendChild(toastXml.CreateTextNode(message));
            //var toastAudioElements = toastXml.GetElementsByTagName("audio");
            //XmlElement audioElement = (XmlElement)toastAudioElements[0];
            IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
            //((XmlElement)toastNode).SetAttribute("duration", "long");
            if (silent)
            {
                XmlElement audio = toastXml.CreateElement("audio");
                audio.SetAttribute("silent", "true");
                toastNode.AppendChild(audio);
            }
            //XmlElement audio = toastXml.CreateElement("audio");
            //audio.SetAttribute("src", "ms-winsoundevent:Notification.Looping.Alarm2");
            //audio.SetAttribute("loop", "true");
            //audio.SetAttribute("silent", "true");
            var toasty = new ToastNotification(toastXml);
            ToastNotificationManager.CreateToastNotifier().Show(toasty);
            return toasty;
        }

        public static string GetEnumDescription(Enum enumObj)
        {
            FieldInfo fieldInfo = enumObj.GetType().GetRuntimeField(enumObj.ToString());

            object[] attribArray = fieldInfo.GetCustomAttributes(false).ToArray();

            if (attribArray.Length == 0)
            {
                return enumObj.ToString();
            }
            else
            {
                EnumDescriptionAttribute attrib = attribArray[0] as EnumDescriptionAttribute;
                return attrib.Description;
            }
        }

        public static Dictionary<string, Windows.UI.Color> GetSystemColors()
        {
            var _Colors = typeof(Windows.UI.Colors)
                // using System.Reflection;
                .GetRuntimeProperties()
                .Select(c => new
                {
                    Color = (Windows.UI.Color)c.GetValue(null),
                    Name = c.Name
                });
            return _Colors.ToDictionary(x => x.Name, x => x.Color);
        }

        public static async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
        {
            var bitmapImage = new BitmapImage();

            var stream = new InMemoryRandomAccessStream();
            await stream.WriteAsync(byteArray.AsBuffer());
            stream.Seek(0);

            bitmapImage.SetSource(stream);
            return bitmapImage;
        }

        public static bool FileExistsSync(Uri uri)
        {
            bool fileExists;
            try
            {
                //   StorageFile file = rootFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
                StorageFile file = StorageFile.GetFileFromApplicationUriAsync(uri).AsTask().ConfigureAwait(false).GetAwaiter().GetResult(); ;
                fileExists = file != null;
            }
            catch
            {
                fileExists = false;
            }
            return fileExists;
        }
        public static bool FileExistsSync(string fileName, StorageFolder rootFolder)
        {
            bool fileExists;
            try
            {
                StorageFile file = rootFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();

                fileExists = file != null;
            }
            catch
            {
                fileExists = false;
            }
            return fileExists;
        }

        public static async Task<StorageFile> SaveImageToStorage(StorageFolder folder, byte[] imageByte, string filename, CreationCollisionOption options = CreationCollisionOption.OpenIfExists)
        {
            StorageFile file = null;

            try
            {
                file = await folder.CreateFileAsync(filename, options);
                await Windows.Storage.FileIO.WriteBytesAsync(file, imageByte);
            }
            catch (Exception ex)
            {
                Logger.GetLogger().ErrorException(ex.Message, ex);
            }

            return file;
        }



        public static async Task<BitmapImage> LoadAvatarFromIsolatedStorage(string username, string filename)
        {
            //StorageFolder folder = await GetAvatarStorageFolderForUser(username);
            StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appdata:///local/" + username + "/Avatars/" + filename));
            return await LoadBitmapImageFromIsolatedStorage(file);//(await folder.GetFileAsync(filename));
        }
        public static async Task<BitmapImage> LoadBitmapImageFromIsolatedStorage(StorageFile file)
        {
            BitmapImage bi = new BitmapImage();
            if (file != null)
            {
                using (var stream = await file.OpenReadAsync())
                    await bi.SetSourceAsync(stream);
            }
            return bi;
        }

        public static async Task<WriteableBitmap> LoadWritableBitmapFromIsolatedStorage(StorageFile file)
        {
            if (file != null)
            {
                using (var stream = await file.OpenReadAsync())
                {
                    BitmapImage bi = new BitmapImage();

                    await bi.SetSourceAsync(stream);
                    WriteableBitmap wb = new WriteableBitmap(bi.PixelWidth, bi.PixelHeight);
                    await wb.SetSourceAsync(stream);
                    return wb;
                }
            }
            return null;
        }
        public static async Task<StorageFolder> GetStorageFolderForUser(string username)
        {
            StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
            StorageFolder userFolder = await rootFolder.CreateFolderAsync(username, CreationCollisionOption.OpenIfExists);

            return userFolder;
        }
        public static async Task<StorageFolder> GetEmoticonStorageFolderForUser(string username)
        {
            StorageFolder rootFolder = await GetStorageFolderForUser(username).ConfigureAwait(false);
            StorageFolder folder = await rootFolder.CreateFolderAsync(StaticSettings.CustomEmoticonFolder, CreationCollisionOption.OpenIfExists);
            return folder;
        }
        public static async Task<StorageFolder> GetAvatarStorageFolderForUser(string username)
        {
            StorageFolder rootFolder = await GetStorageFolderForUser(username).ConfigureAwait(false);
            StorageFolder folder = await rootFolder.CreateFolderAsync(StaticSettings.AvatarFolder, CreationCollisionOption.OpenIfExists);
            return folder;
        }
        public static async Task<StorageFolder> GetTabImageStorageFolder()
        {
            StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
            StorageFolder tabFolder = tabFolder = await rootFolder.CreateFolderAsync(StaticSettings.TabImageFolder, CreationCollisionOption.OpenIfExists);
            return tabFolder;
        }

        //public static async Task<IRandomAccessStream> LoadImageResourceAsStream(string path)
        //{
        //    var storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync(path.Replace('/', '\\'));
        //    var stream = await storageFile.OpenReadAsync();

        //    return stream;
        //}

        public static async Task<Byte[]> LoadImageData(string filename, StorageFolder folder)
        {
            try
            {
                StorageFile file = await folder.GetFileAsync(filename);
                return await LoadImageData(file);
            }
            catch (Exception err)
            {
                Debug.WriteLine(err);
                return null;
            }
        }

        public static async Task<byte[]> LoadImageData(IRandomAccessStream fileStream)
        {
            var reader = new DataReader(fileStream.GetInputStreamAt(0));
            var bytes = new Byte[fileStream.Size];
            await reader.LoadAsync((uint)fileStream.Size);
            reader.ReadBytes(bytes);
            return bytes;
        }

        public static async Task<Byte[]> LoadImageData(StorageFile file)
        {
            try
            {
                if (file == null)
                    return null;

                var bytes = new Byte[0];
                using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
                {
                    return await LoadImageData(fileStream);
                }
            }
            catch (Exception err)
            {
                Debug.WriteLine(err);
                return null;
            }
        }
        public static string FileNameFriendly(string n)
        {
            n = n.Replace("*", "~");
            n = n.Replace("|", "-");
            n = n.Replace(@"\", "'");
            n = n.Replace("/", "_");
            n = n.Replace(":", ".");
            n = n.Replace("<", "(");
            n = n.Replace(">", ")");
            n = n.Replace("?", "^");
            n = n.Replace('"'.ToString(), "");
            n = n.Trim();
            return n;
        }
        public static Color ConvertColor(Color c)
        {
            //SolidColorBrush temp = new SolidColorBrush(c);
            if (c == Colors.Red)
                return PhoneThemeColors.Red;
            else if (c == Colors.Blue)
                return PhoneThemeColors.Cobalt;
            else if (c == Colors.Green)
                return PhoneThemeColors.Emerald;
            else if (ColorToHexString(c) == "#FF800000")
                return PhoneThemeColors.Crimson;
            else if (c == Colors.Magenta)
                return PhoneThemeColors.Magenta;
            else if (ColorToHexString(c) == "#FF808000")
                return PhoneThemeColors.Olive;
            else if (ColorToHexString(c) == "#FF000080")
                return PhoneThemeColors.Cobalt;
            else if (c == Colors.Purple)
                return PhoneThemeColors.Violet;
            else if (ColorToHexString(c) == "#FF008080")
                return PhoneThemeColors.Teal;
            else if (c == Colors.Gray)
                return PhoneThemeColors.Steel;
            else if (ColorToHexString(c) == "#FF00FF00")
                return PhoneThemeColors.Lime;
            else if (c == Colors.Yellow)
                return PhoneThemeColors.Yellow;
            else if (ColorToHexString(c) == "#FFFF00FF")
                return PhoneThemeColors.Pink;
            else if (ColorToHexString(c) == "FF00FFFF")
                return PhoneThemeColors.Cyan;

            else return c;
        }




        public static string ObjectToString<T>(T input)
        {
            var settings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                ObjectCreationHandling = ObjectCreationHandling.Auto,
                Formatting = Formatting.None
            };

            return Newtonsoft.Json.JsonConvert.SerializeObject(input, settings);
        }

        public static T StringToObject<T>(string input)
        {
            if (String.IsNullOrEmpty(input))
                return default(T);

            try
            {
                var settings = new JsonSerializerSettings()
                {
                    TypeNameHandling = TypeNameHandling.All,
                    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                    ObjectCreationHandling = ObjectCreationHandling.Auto,
                    Formatting = Formatting.None
                };
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(input, settings);
            }
            catch { return default(T); }
        }
        public static List<string> SplitLongMessage(string str, int chunkSize)
        {
            if (str.Length < chunkSize)
                return null;
            int totalLength = str.Length;
            List<string> strList = new List<string>();
            int i = 0;
            while (true)
            {
                if ((totalLength - i) < chunkSize)
                {
                    strList.Add(str.Substring(i, totalLength - i));
                    break;
                }
                string sub = str.Substring(i, chunkSize);
                int lastSpaceIndex = sub.LastIndexOf(' ');
                if (lastSpaceIndex == -1)
                    lastSpaceIndex = 400;

                strList.Add(str.Substring(i, lastSpaceIndex));
                i += lastSpaceIndex;


            }
            return strList;
        }

        public static int RandomNumber(int from, int to)
        {
            Random r = new Random(DateTime.Now.Millisecond);
            return r.Next(from, to);

        }
        //public static string CombinePath(params object[] values)
        //{
        //    string path = "";
        //    foreach (var str in values)
        //    {
        //        path += str.ToString().TrimStart(StaticSettings.DirectorySeparatorChar).EndsWith(StaticSettings.DirectorySeparatorChar.ToString()) ? str : str.ToString() + StaticSettings.DirectorySeparatorChar;
        //    }

        //    return path.TrimEnd(StaticSettings.DirectorySeparatorChar);
        //}


        public static bool IsValidEmail(string emailString)
        {
            return Regex.IsMatch(emailString,
                    @"^(?("")(""[^""]+?""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                    @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9]{2,17}))$",
                    RegexOptions.IgnoreCase);
        }
        public static string GetCustomEmoticonPath(string username, string filename)
        {
            return string.Format("ms-appdata:///local/{0}/{1}/{2}", username, StaticSettings.CustomEmoticonFolder, filename);
        }

        public static string DictionaryToString<TK, TV>(Dictionary<TK, TV> input)
        {
            MemoryStream stream = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Dictionary<TK, TV>));

            ser.WriteObject(stream, input);
            byte[] bytes = stream.ToArray();
            string str = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
            stream.Dispose();
            return str;
        }
        public static string ListToString<T>(List<T> input)
        {
            MemoryStream stream = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<T>));
            ser.WriteObject(stream, input);
            byte[] bytes = stream.ToArray();
            string str = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
            stream.Dispose();
            return str;
        }
        public static Dictionary<TK, TV> StringToDictionary<TK, TV>(string input)
        {
            if (String.IsNullOrEmpty(input))
                return new Dictionary<TK, TV>();
            MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));

            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Dictionary<TK, TV>));
            Dictionary<TK, TV> dic = (Dictionary<TK, TV>)ser.ReadObject(stream);
            stream.Dispose();
            return dic;
        }
        public static List<T> StringToList<T>(string input)
        {
            if (String.IsNullOrEmpty(input))
                return new List<T>();
            MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<T>));
            List<T> lst = (List<T>)ser.ReadObject(stream);
            stream.Dispose();
            return lst;
        }


        public static string ColorToHexString(Color color)
        {
            byte[] bytes = new byte[3];
            bytes[0] = color.R;
            bytes[1] = color.G;
            bytes[2] = color.B;
            char[] chars = new char[bytes.Length * 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                int b = bytes[i];
                chars[i * 2] = HexDigits[b >> 4];
                chars[i * 2 + 1] = HexDigits[b & 0xF];
            }
            string str = "#FF" + new string(chars);
            return str;
        }

        private static readonly char[] HexDigits = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

        public static FontWeight ParseFontWeight(string str)
        {
            if (str == null)
                str = "";
            switch (str.ToLower())
            {
                case "black":
                    return FontWeights.Black;
                case "bold":
                    return FontWeights.Bold;
                case "extrablack":
                    return FontWeights.ExtraBlack;
                case "extrabold":
                    return FontWeights.ExtraBold;
                case "extralight":
                    return FontWeights.ExtraLight;
                case "light":
                    return FontWeights.Light;
                case "medium":
                    return FontWeights.Medium;
                default:
                case "normal":
                    return FontWeights.Normal;
                case "semibold":
                    return FontWeights.SemiBold;
                case "semilight":
                    return FontWeights.SemiLight;
                case "thin":
                    return FontWeights.Thin;

            }
        }


        public static Color HexStringToColor(String hex)
        {
            if (String.IsNullOrEmpty(hex))
                return Colors.White;
            //remove the # at the front
            hex = hex.Replace("#", "");

            byte a = 255;
            byte r = 255;
            byte g = 255;
            byte b = 255;

            int start = 0;

            //handle ARGB strings (8 characters long)
            if (hex.Length == 8)
            {
                a = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                start = 2;
            }

            //convert RGB characters to bytes
            r = byte.Parse(hex.Substring(start, 2), System.Globalization.NumberStyles.HexNumber);
            g = byte.Parse(hex.Substring(start + 2, 2), System.Globalization.NumberStyles.HexNumber);
            b = byte.Parse(hex.Substring(start + 4, 2), System.Globalization.NumberStyles.HexNumber);

            return Color.FromArgb(a, r, g, b);
        }
        public static string EncodePassword(string password)
        {
            var provider = Windows.Security.Cryptography.Core.HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1);
            CryptographicHash objHash = provider.CreateHash();
            IBuffer buffMsg1 = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
            objHash.Append(buffMsg1);
            IBuffer buffHash1 = objHash.GetValueAndReset();
            return CryptographicBuffer.EncodeToHexString(buffHash1);

        }

        public static async Task<string> ComputeMD5Async(byte[] data)
        {
            Task<string> t = Task.Factory.StartNew(() =>
                {
                    var alg = HashAlgorithmProvider.OpenAlgorithm("MD5");
                    IBuffer buff = CryptographicBuffer.CreateFromByteArray(data);
                    var hashed = alg.HashData(buff);
                    var res = CryptographicBuffer.EncodeToHexString(hashed);
                    return res;
                });
            return await t.ConfigureAwait(false);
        }
    }
}
